// Copyright (C) Kumo inc. and its affiliates.
// Author: Jeff.li lijippy@163.com
// All rights reserved.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.
//


#pragma once

#include <chrono>
#include <functional>
#include <optional>

namespace kumo::pollux::dwio::common {
    class MeasureTime {
    public:
        explicit MeasureTime(
            const std::function<void(std::chrono::high_resolution_clock::duration)> &
            callback)
            : callback_{callback},
              startTime_{std::chrono::high_resolution_clock::now()} {
        }

        MeasureTime(const MeasureTime &) = delete;

        MeasureTime(MeasureTime &&) = delete;

        MeasureTime &operator=(const MeasureTime &) = delete;

        MeasureTime &operator=(MeasureTime &&other) = delete;

        ~MeasureTime() {
            callback_(std::chrono::high_resolution_clock::now() - startTime_);
        }

    private:
        const std::function<void(std::chrono::high_resolution_clock::duration)> &
        callback_;
        const std::chrono::time_point<std::chrono::high_resolution_clock> startTime_;
    };

    // Make sure you don't pass a lambda to this function, because that will cause a
    // std::function to be created on the fly (implicitly), and when we return from
    // this function that std::function won't exist anymore. So when MeasureTime is
    // destroyed, it will try to access a non-existing std::function.
    inline std::optional<MeasureTime> measureTimeIfCallback(
        const std::function<void(std::chrono::high_resolution_clock::duration)> &
        callback) {
        if (callback) {
            return std::make_optional<MeasureTime>(callback);
        }
        return std::nullopt;
    }
} // namespace kumo::pollux::dwio::common
